package com.sc.commons.base.repository;

import com.sc.commons.base.dto.BasePageReq;
import org.springframework.stereotype.Repository;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;


/**
 * 原则：
 * 以entity结尾的查询，都是以泛型类返回
 * 不以entity结尾的查询，都必须传入类型，会自动反射为该类型。
 * NoResultException往上抛。请在全局异常里捕捉
 * @author lenovo
 * @param <T>
 */
@Repository
public class BaseRepositoryImpl<T> implements BaseRepository<T> {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public void save(T o) {
        if(BaseEntity.class.isAssignableFrom(o.getClass())) {
            BaseEntity b = (BaseEntity) o;
            b.setCreateDateTime(LocalDateTime.now());
            b.setModifyDateTime(b.getCreateDateTime());
        }
        entityManager.persist(o);
    }

    @Override
    public void update(T o) {
        if(BaseEntity.class.isAssignableFrom(o.getClass())) {
            BaseEntity b = (BaseEntity) o;
            b.setModifyDateTime(b.getCreateDateTime());
        }
        entityManager.merge(o);
    }

    @Override
    public void delete(T o) {
        if (o != null) {
            entityManager.remove(o);
        }
    }

    @Override
    public T loadEntity(Class<T> c, Serializable id) {
        return entityManager.getReference(c, id);
    }

    @Override
    public T getEntity(Class<T> userClass, Serializable l) {
        return entityManager.find(userClass, l);
    }
    @Override
    public T getEntity(String jpql) {
        Query q = entityManager.createQuery(jpql);
        return (T) q.getSingleResult();
    }
    @Override
    public T getEntity(String jpql, Object... params) {
        Query q = entityManager.createQuery(jpql);
        if (params != null && params.length > 0) {
            for (int i = 0; i < params.length; i++) {
                q.setParameter(i + 1, params[i]);
            }
        }
        return (T) q.getSingleResult();
    }
    @Override
    public T getEntity(String jpql, Map<String, Object> params) {
        Query q = entityManager.createQuery(jpql);
        if (params != null && !params.isEmpty()) {
            for (String key : params.keySet()) {
                q.setParameter(key, params.get(key));
            }
        }
        return (T) q.getSingleResult();
    }

    @Override
    public <O> O get(Class<O> clazz, String jpql){
        return entityManager.createQuery(jpql, clazz).getSingleResult();
    };
    @Override
    public <O> O get(Class<O> clazz, String jpql, Map<String, Object> params){
        TypedQuery<O> query = entityManager.createQuery(jpql, clazz);
        if (params != null && !params.isEmpty()) {
            for (String key : params.keySet()) {
                query.setParameter(key, params.get(key));
            }
        }
        return query.getSingleResult();
    };

    @Override
    public <O> O get(Class<O> clazz, String jpql, Object... params){
        TypedQuery<O> query = entityManager.createQuery(jpql, clazz);
        if (params != null && params.length > 0) {
            for (int i = 0; i < params.length; i++) {
                query.setParameter(i + 1, params[i]);
            }
        }
        return query.getSingleResult();
    }

    @Override
    public List<T> findEntity(String jpql) {
        Query q = entityManager.createQuery(jpql);
        return q.getResultList();
    }

    @Override
    public List<T> findEntity(String jpql, Map<String, Object> params) {
        Query q = entityManager.createQuery(jpql);
        if (params != null && !params.isEmpty()) {
            for (String key : params.keySet()) {
                Object obj = params.get(key);
                q.setParameter(key, obj);
            }
        }
        return q.getResultList();
    }

    @Override
    public List<T> findEntity(BasePageReq page, String jpql, Map<String, Object> params) {
        Query q = entityManager.createQuery(jpql);
        if (params != null && !params.isEmpty()) {
            for (String key : params.keySet()) {
                Object obj = params.get(key);
                q.setParameter(key, obj);
            }
        }
        return q.setFirstResult((page.getPage() - 1) * page.getRows()).setMaxResults(page.getRows()).getResultList();
    }

    @Override
    public List<T> findEntity(String jpql, Object... params) {
        Query q = entityManager.createQuery(jpql);
        if (params != null && params.length > 0) {
            for (int i = 0; i < params.length; i++) {
                q.setParameter(i + 1, params[i]);
            }
        }
        return q.getResultList();
    }

    @Override
    public List<T> findEntity(BasePageReq page, String jpql, Object... params) {
        Query q = entityManager.createQuery(jpql);
        if (params != null && params.length > 0) {
            for (int i = 0; i < params.length; i++) {
                q.setParameter(i + 1, params[i]);
            }
        }
        return q.setFirstResult((page.getPage() - 1) * page.getRows()).setMaxResults(page.getRows()).getResultList();
    }

    @Override
    public <O> List<O> find(Class<O> clazz, String jpql) {
        Query q = entityManager.createQuery(jpql, clazz);
        return q.getResultList();
    }

    @Override
    public <O> List<O> find(Class<O> clazz, String jpql, Map<String, Object> params) {
        Query q = entityManager.createQuery(jpql, clazz);
        if (params != null && !params.isEmpty()) {
            for (String key : params.keySet()) {
                Object obj = params.get(key);
                q.setParameter(key, obj);
            }
        }
        return q.getResultList();
    }

    @Override
    public <O> List<O> find(Class<O> clazz, BasePageReq page, String jpql, Map<String, Object> params) {
        Query q = entityManager.createQuery(jpql, clazz);
        if (params != null && !params.isEmpty()) {
            for (String key : params.keySet()) {
                Object obj = params.get(key);
                q.setParameter(key, obj);
            }
        }
        return q.setFirstResult((page.getPage() - 1) * page.getRows()).setMaxResults(page.getRows()).getResultList();
    }

    @Override
    public <O> List<O> find(Class<O> clazz, String jpql, Object... params) {
        Query q = entityManager.createQuery(jpql, clazz);
        if (params != null && params.length > 0) {
            for (int i = 0; i < params.length; i++) {
                q.setParameter(i + 1, params[i]);
            }
        }
        return q.getResultList();
    }

    @Override
    public <O> List<O> find(Class<O> clazz, BasePageReq page, String jpql, Object... params) {
        Query q = entityManager.createQuery(jpql, clazz);
        if (params != null && params.length > 0) {
            for (int i = 0; i < params.length; i++) {
                q.setParameter(i + 1, params[i]);
            }
        }
        return q.setFirstResult((page.getPage() - 1) * page.getRows()).setMaxResults(page.getRows()).getResultList();
    }

    @Override
    public List find(JpaQueryUtils jpaQueryUtils) {
        Query q = entityManager.createQuery(jpaQueryUtils.getJpql(), jpaQueryUtils.getClazz());
        Map<String, Object> params = jpaQueryUtils.getParams();
        if (params != null && !params.isEmpty()) {
            for (String key : params.keySet()) {
                Object obj = params.get(key);
                // 这里考虑传入的参数是什么类型，不同类型使用的方法不同
                q.setParameter(key, obj);
            }
        }
        if(jpaQueryUtils.getPage()!= null && jpaQueryUtils.getRows()!= null){
            q.setFirstResult((jpaQueryUtils.getPage() - 1) * jpaQueryUtils.getRows()).setMaxResults(jpaQueryUtils.getRows());
        }

        return q.getResultList();
    }

    @Override
    public int execute(String jpql) {
        Query q = entityManager.createQuery(jpql);
        return q.executeUpdate();
    }

    @Override
    public int execute(String jpql, Map<String, Object> params) {
        Query q = entityManager.createQuery(jpql);
        if (params != null && !params.isEmpty()) {
            for (String key : params.keySet()) {
                Object obj = params.get(key);
                // 这里考虑传入的参数是什么类型，不同类型使用的方法不同
                q.setParameter(key, obj);
            }
        }
        return q.executeUpdate();
    }

    @Override
    public int execute(String jpql, Object... params) {
        Query q = entityManager.createQuery(jpql);
        if (params != null && params.length > 0) {
            for (int i = 0; i < params.length; i++) {
                q.setParameter(i + 1, params[i]);
            }
        }
        return q.executeUpdate();
    }

    @Override
    public Long count(String jpql) {
        Query q = entityManager.createQuery(jpql);
        return (long) q.getSingleResult();
    }

    @Override
    public Long count(String jpql, Object... params) {
        Query q = entityManager.createQuery(jpql);
        if (params != null && params.length > 0) {
            for (int i = 0; i < params.length; i++) {
                q.setParameter(i + 1, params[i]);
            }
        }
        return (Long) q.getSingleResult();
    }

    @Override
    public Long count(String jpql, Map<String, Object> params) {
        Query q = entityManager.createQuery(jpql);
        if (params != null && !params.isEmpty()) {
            for (String key : params.keySet()) {
                Object obj = params.get(key);
                q.setParameter(key, obj);
            }
        }
        return (long) q.getSingleResult();
    }


}
